﻿using System.Collections.Generic;
using System.Linq;
using CardPlay.Model.ActionModel;
using CardPlay.Model.GameModel;
using CardPlay.Model.GameModel.Presentation;
using CardPlay.Model.Layout;
using CardPlay.Model.Primitives;

namespace CardPlay.DemoPack.Games.PairingVariants
{
    public abstract class SpatialPairingStyleGame : PairingStyleGame
    {
        protected SpatialPairingStyleGame()
        {
            NamesOfAdditionalPiles.Add(Stock);
        }

        public override ILayoutSite CreatePresentation(IPresentationContext presentation)
        {
            var metrics = presentation.Metrics;
            var tableauStyle = new VisualTraits
            {
                Arrangement = CardArrangement.StackSquare,
                EmptyCue = () => EmptyPileCue.CardSite,
                ContentFit = ContentFit.FitBounds,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                MinimumSize = metrics.CardSize + new Size(metrics.MinSpacingAcross, metrics.MinSpacingDown)
            };


            var root = presentation.CreateRowLayout();

            root.Add(presentation.CreatePileVisual(Stock, presentation.StyleForStock(this)));
            root.Add(presentation.CreateMimimalSpacer());

            var tableau = new UniformGridLayout { Columns = TableauColumns, Rows = TableauRows };
            root.Add(tableau);

            presentation.AddPiles(tableau, NamesOfTableaus, tableauStyle);
            return root;
        }

        protected abstract IEnumerable<PartLocation[]> DiscardablePairs { get; }

        protected abstract IAction CreateDealAction();

        protected override IAction QueryActionAt(PartLocation location)
        {
            return location.Matches(Stock) ? CreateDealAction() : base.QueryActionAt(location);
        }

        protected override bool IsChangeSelectionAllowedAt(PartLocation location)
        {
            if (Selection.Contains(location)) return true;

            var pile = PileAt(location);
            if (pile == null || pile.IsEmpty || location != pile.Top || !pile.TopCard.IsFaceUp) return false;

            return 
                (Selection.Count == 0 && DiscardablePairs.Any(pair => pair.Contains(location))) || 
                (Selection.Count == 1 && IsSelectionDiscardable(new[] {location, Selection[0]}));
        }

        protected override bool IsSelectionDiscardable(IEnumerable<PartLocation> selection)
        {
            return DiscardablePairs.Any(pair => pair.Intersect(selection).Count() == pair.Length);
        }

        protected int TableauColumns { get; set; }

        protected int TableauRows
        {
            get { return TotalTableaus / TableauColumns; }
            set { TotalTableaus = value * TableauColumns; }
        }

        protected string TableauNameAt(int col, int row)
        {
            return StandardPileNames.PrefixForTableau + (row * TableauColumns + col + 1);
        }

        protected Point PointFromTableauLocation(PartLocation location)
        {
            var index = location.GetOrdinal() - 1;
            return new Point(index % TableauColumns, index / TableauColumns);
        }

    }
}